﻿using System.Linq;
using Xenta.Operations;

namespace Xenta.Security
{
    /// <summary>
    /// Exposes the securirty auditor interface.
    /// </summary>
    /// <remarks>
    /// The security auditor allows to verify that an operation is 
    /// allowed to be executed using specific working context.
    /// </remarks>
    public interface ISecurityAuditor
    {
        #region Methods

        /// <summary>
        /// Uses the working context to determine, if 
        /// the operation is allowed for execution.
        /// </summary>
        /// <param name="ctx">The working context.</param>
        /// <param name="uow">The unit of work.</param>
        /// <param name="operation">The operation instance.</param>
        /// <returns>
        /// true, if context is safe or any of security policy
        /// is satisfied; otherwise false.
        /// </returns>
        bool Audit(IWorkingContext ctx, IUnitOfWork uow, ISecuredOperation operation);

        #endregion
    }

    /// <summary>
    /// The ISecurityAuditor implementation.
    /// </summary>
    public class SecurityAuditorImpl : ISecurityAuditor
    {
        #region Methods

        /// <summary>
        /// Uses the working context to determine, if 
        /// the operation is allowed for execution.
        /// </summary>
        /// <param name="ctx">The working context.</param>
        /// <param name="uow">The unit of work.</param>
        /// <param name="operation">The operation instance.</param>
        public bool Audit(IWorkingContext ctx, IUnitOfWork uow, ISecuredOperation operation)
        {
            if(ctx.IsSafe)
                return true;

            var rules = operation.SecurityPolicies;

            if(rules == null || !rules.Any())
                return true;
            return rules.Any(i => i.All(x => x.DoesPass(ctx, uow)));
        }

        #endregion
    }
}
